%{ open Ast %}

/* TODO: rules are not implemented, like, at all */

%token CHILDREN PARENTS CHILD PARENT INEDGES OUTEDGES INEDGE OUTEDGE INNODE 
OUTNODE
%token EXC LPAREN RPAREN LBRACE RBRACE COMMA SEMI NEG PLUS MINUS TIMES DIVIDE 
MOD
%token LBRACK RBRACK OR AND EOF DOT QUOTE DOLR
%token ASSIGN EQ NEQ LT LEQ GT GEQ CNCT REDGE LEDGE UEDGE
%token ADD ADDBY ADDFRONT ADDBYFRONT COMP CRAWL EDGE ELSE
%token FOR FLOAT FROM IN INT IF NODE OPT ORDER OUT PRINT QUEUE RULE STR CALL
%token CALL SET
%token WHILE WITH 
%token <int> LITINT
%token <float> LITFLT
%token <string> ID
%token <string> LITSTR

%nonassoc NOELSE
%nonassoc ELSE
%nonassoc NOPAREN
%right ASSIGN
%left AND OR
%left EQ NEQ
%left LT GT LEQ GEQ 
%left PLUS MINUS
%left TIMES DIVIDE MOD

%start program
%type <Ast.program> program

%%

/*
program:
					{ [], [] }
|	program fdecl				{ fst $1, ($2 :: snd $1) }
*/

program:
	/* nothing */				{ [] }
|	program fdecl				{ $2 :: $1 }

fdecl:
	OPT ID LPAREN formals_opt RPAREN LBRACE stmt_list RBRACE
	{ { func_type = "opt"; fname = $2; formals = $4; body = List.rev $7 } }
|	CRAWL ID LPAREN formals_opt RPAREN LBRACE stmt_list RBRACE
	{ { func_type = "crawl"; fname = $2; formals = $4; body = List.rev $7 } 
}
|	RULE ID LBRACE stmt_list RBRACE
	{ { func_type = "rule"; fname = $2; formals = []; body = List.rev $4 } 
}

/* dvp: the List.rev is from how we untangle the formals in
formal_list */

formals_opt:
	/* nothing */				{ [] }
|	formal_list				{ List.rev $1 }




formal:
	OUT INT ID				{ Validate(Out,Int,$3) }
|	OUT NODE ID				{ Validate(Out,Node,$3) }
|	OUT EDGE ID				{ Validate(Out,Edg,$3) }
|	OUT STR ID				{ Validate(Out,Str,$3) }
|	OUT FLOAT ID				{ Validate(Out,Flt,$3) }
|	IN INT ID				{ Validate(In,Int,$3) }
|	IN NODE ID				{ Validate(In,Node,$3) }
|	IN EDGE ID				{ Validate(In,Edg,$3) }
|	IN STR ID				{ Validate(In,Str,$3) }
|	IN FLOAT ID				{ Validate(In,Flt,$3) }



formal_list:
	formal					{ [$1] }
|	formal_list SEMI formal			{ $3 :: $1 }

stmt_list:
	/* nothing */				{ [] }
|	stmt_list stmt				{ $2 :: $1 }

variable:
	ID					{ VarId($1) }
|	variable DOT ID				{ RecVar($1, $3) }
|	ID LBRACK LITINT RBRACK  		{ ArrayIndStat($1,$3)}
|	ID LBRACK variable RBRACK  		{ ArrayIndDyn($1,$3)}

stmt:
 	expr EXC				{ Expr($1) }
|	IF LPAREN expr RPAREN LBRACE stmt_list RBRACE %prec NOELSE { If($3, 
List.rev $6,[]) }
|	IF LPAREN expr RPAREN LBRACE stmt_list RBRACE ELSE LBRACE stmt_list 
RBRACE { If($3, List.rev $6, List.rev $10) }
|	WHILE LPAREN expr RPAREN LBRACE stmt_list RBRACE 		{ 
While($3, List.rev $6) }
|	INT variable EXC				{ Declare_Only(Int, $2) 
}
|	NODE variable EXC				{ Declare_Only(Node, 
$2) }
|	EDGE variable EXC				{ Declare_Only(Edg, $2) 
}
|	STR variable EXC				{ Declare_Only(Str, $2) 
}
|	FLOAT variable EXC				{ Declare_Only(Flt, $2) 
}
|	INT variable ASSIGN expr EXC			{ Declare(Int, $2, $4) 
}
|	NODE variable ASSIGN expr EXC			{ Declare(Node, $2, $4) 
}
|	EDGE variable ASSIGN expr EXC			{ Declare(Edg, $2, $4) 
}
|	STR variable ASSIGN expr EXC			{ Declare(Str, $2, $4) 
}
|	FLOAT variable ASSIGN expr EXC			{ Declare(Flt, $2, $4) 
}
|  NODE variable ASSIGN CNCT tree CNCT EXC	{ CreateGraph($2, $5) } 
|	ID LPAREN actuals_opt RPAREN EXC		{ Call($1, $3) }
|	PRINT LPAREN actuals_opt RPAREN	EXC		{ Print($3) }

|	ID LPAREN actuals_opt RPAREN FROM variable WITH ID EXC {Crawl($1, $3, $6, $8)}
|	variable LEDGE variable EXC {EdgeCreation($1, Ledge, $3) }
|	variable REDGE variable EXC {EdgeCreation($1, Redge, $3) }
|	variable UEDGE variable EXC {EdgeCreation($1, Uedge, $3) }
|	variable ASSIGN expr EXC			{ Assign($1, $3) }
|	CALL EXC				{ CallRule }
|	SET ID EXC		{ SetRule($2) }	
|	ADD LPAREN variable RPAREN EXC			{ RAdd($3) }
|	ADDFRONT LPAREN variable RPAREN EXC								{ RAddFront($3) }
|	ADDBY LPAREN NODE DOT ID COMMA DOLR COMMA LITINT RPAREN EXC{ RAddBy($5, AddByNode, Dolr, $9) }
|	ADDBY LPAREN NODE DOT ID COMMA NEG COMMA LITINT RPAREN EXC	{ RAddBy($5, AddByNode, Tilde, $9) }
|	ADDBYFRONT LPAREN NODE DOT ID COMMA DOLR COMMA LITINT RPAREN EXC{ RAddByFront($5, AddByNode, Dolr, $9) }
|	ADDBYFRONT LPAREN NODE DOT ID COMMA NEG COMMA LITINT RPAREN EXC{ RAddByFront($5, AddByNode, Tilde, $9) }


expr:
	LPAREN expr RPAREN			{ $2 }
|	plainString				{ Lit_Str($1) }
|	LITINT					{ Lit_Int($1) }
|	LITFLT					{ Lit_Flt($1) }
|	expr PLUS expr				{ Binop($1, Add, $3) }
|	expr MINUS expr				{ Binop($1, Sub, $3) }
|	expr TIMES expr				{ Binop($1, Mult, $3) }
|	expr DIVIDE expr			{ Binop($1, Div, $3) }
|	expr EQ expr				{ Binop($1, Equal, $3) }
|	expr NEQ expr				{ Binop($1, Neq, $3) }
|	expr LT expr				{ Binop($1, Less, $3) }  
|	expr LEQ expr				{ Binop($1, Leq, $3) }
|	expr GT expr				{ Binop($1, Greater, $3) }
|	expr GEQ expr				{ Binop($1, Geq, $3) }
|	expr AND expr				{ Binop($1, And, $3 ) }
|	expr OR expr				{ Binop($1, Or, $3 ) }
|	expr MOD expr				{ Binop($1, Mod, $3) }
|	LBRACE actuals_list RBRACE		{ Actuals($2)} 
|	variable DOT OUTEDGE LPAREN expr RPAREN     { NodeOutEdge($1,$5) }
|	variable DOT INEDGE LPAREN expr RPAREN      { NodeInEdge($1,$5) }
|	variable DOT CHILD LPAREN expr RPAREN     { NodeChild($1,$5) }
|	variable DOT PARENT LPAREN expr RPAREN      { NodeParent($1,$5) }
|	variable DOT OUTEDGES                         { NodeOutEdges($1) }
|	variable DOT INEDGES                          { NodeInEdges($1) }
|       variable DOT INNODE                           { EdgeInNode($1) }
|       variable DOT OUTNODE                          { EdgeOutNode($1) }
|	variable				{ Variable($1) }

tree:
   headnode			{Leaf($1)}
|  headnode REDGE children	{SubTree($1, Redge, $3)}
|  headnode LEDGE children	{SubTree($1, Ledge, $3)}
|  headnode UEDGE children	{SubTree($1, Uedge, $3)}

headnode:
  LITINT {$1}

children:
  nodetree {[$1]}
| nodetree COMMA children {$1 :: $3}

nodetree:
  LITINT {Leaf($1)}
| LPAREN tree RPAREN {$2}

plainString:
	LITSTR					{ $1 }

actuals_opt:
	/* nothing */				{ [] }
|	actuals_list				{ List.rev $1 }

actuals_list:
	expr					{ [$1] }
|	actuals_list SEMI expr			{ $3 :: $1 }
